﻿//-----------------------------------------------------------------------
// <copyright file="CleanActEngine.cs" company="FastNET Services">
//     Copyright (c) 2007-2009. All Rights Reserved.
// </copyright>
// <license>
//     GPLv2
// </license>
// <warranty>
//     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
//     BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
//     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
//     DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//     OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// </warranty>
//-----------------------------------------------------------------------
#region Usings

using System;
using System.ServiceProcess;
using System.Threading;
using FastNET.CleanAct.Client.ManagerEngine.Managers;
using FastNET.CleanAct.Common.EngineModel.Managers.Interface;

#endregion

namespace FastNET.CleanAct.Client.ManagerEngine
{
    /// <summary>
    /// Windows Service class for the CleanAct Control Engine
    /// </summary>
    public partial class CleanActControlEngine : ServiceBase
    {
        #region Variables

        private readonly ManualResetEvent _threadSuspended;
        private readonly object _processLock;
        private readonly IServerDataManager _dataManager;
        private readonly ICommunicationManager _communicationManager;

        private Thread _managerThread;

        #endregion

        #region CTor/DTor

        /// <summary>
        /// Initializes a new instance of the CleanActControlEngine class
        /// </summary>
        public CleanActControlEngine()
        {
            InitializeComponent();

            _threadSuspended = new ManualResetEvent(false);
            _dataManager = new ServerDataManager();
            _communicationManager = new ServerCommunicationManager(_dataManager);

            _processLock = new object();
        }

        #endregion

        #region Private Properties

        /// <summary>
        /// Gets a value indicating whether or not the thread status shows it is running
        /// </summary>
        private bool IsAlive
        {
            get
            {
                return _managerThread != null && _managerThread.IsAlive;
            }
        }

        #endregion

        #region Protected Service Overrides

        /// <summary>
        /// When implemented in a derived class, executes when a Start command is sent to the service by the Service Control Manager (SCM)
        /// or when the operating system starts (for a service that starts automatically). Specifies actions to take when the service starts.
        /// </summary>
        /// <param name="args"> Data passed by the start command. </param>
        protected override void OnStart(string[] args)
        {
            StartThread();
            _communicationManager.OpenFactories();

            base.OnStart(args);
        }

        ///<summary>
        /// When implemented in a derived class, executes when a Stop command is sent to the service by the Service Control Manager (SCM).
        /// Specifies actions to take when a service stops running.
        ///</summary>
        protected override void OnStop()
        {
            StopThread();
            _communicationManager.CloseFactories();

            base.OnStop();
        }

        /// <summary>
        /// When implemented in a derived class, <see cref="M:System.ServiceProcess.ServiceBase.OnContinue" /> runs when a Continue command
        /// is sent to the service by the Service Control Manager (SCM). Specifies actions to take when a service resumes normal functioning
        /// after being paused.
        /// </summary>
        protected override void OnContinue()
        {
            ResumeThread();
            _communicationManager.OpenChannels();

            base.OnContinue();
        }

        /// <summary>
        /// When implemented in a derived class, executes when a Pause command is sent to the service by the Service Control Manager (SCM).
        /// Specifies actions to take when a service pauses.
        /// </summary>
        protected override void OnPause()
        {
            PauseThread();
            _communicationManager.CloseChannels();

            base.OnPause();
        }

        #endregion

        #region Private Main Thread Management

        /// <summary>
        /// Starts the manager background thread
        /// </summary>
        private void StartThread()
        {
            if (IsAlive)
            {
                throw new InvalidOperationException("Stop must be called before restarting");
            }

            _managerThread = new Thread(ManagerThread)
            {
                Name = "CleanAct Control Core Thread",
                Priority = ThreadPriority.BelowNormal
            };

            _managerThread.Start();
        }

        /// <summary>
        /// Stops the manager background thread
        /// </summary>
        private void StopThread()
        {
            if (IsAlive)
            {
                _managerThread.Abort();
                _managerThread.Join(60000);
            }

            _managerThread = null;
        }

        /// <summary>
        /// Pauses the next cycle for the background thread
        /// </summary>
        private void PauseThread()
        {
            _threadSuspended.Reset();
        }

        /// <summary>
        /// Resumes the next cycle for the background thread
        /// </summary>
        private void ResumeThread()
        {
            _threadSuspended.Set();
        }

        #endregion

        #region Main Thread

        /// <summary>
        /// Background manager thread for core thread
        /// </summary>
        private void ManagerThread()
        {
            // Catch thread aborting
            try
            {
                while (true)
                {
                    // This is used for pausing the process
                    _threadSuspended.WaitOne();

                    Thread.Sleep(60000);
                }
            }
            catch (ThreadAbortException)
            {

            }
        }

        #endregion
    }
}